Package org.python.pydev.debug.ui.launching

Source Code of org.python.pydev.debug.ui.launching.PythonRunner

/**
* Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the Eclipse Public License (EPL).
* Please see the license.txt included with this distribution for details.
* Any modifications to this file must keep this entire header intact.
*/
/*
* Author: atotic
* Created on Mar 18, 2004
*/
package org.python.pydev.debug.ui.launching;

import java.io.File;
import java.io.IOException;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.HashMap;
import java.util.Map;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.model.IProcess;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Display;
import org.python.copiedfromeclipsesrc.JDTNotAvailableException;
import org.python.pydev.core.log.Log;
import org.python.pydev.debug.core.Constants;
import org.python.pydev.debug.core.PydevDebugPlugin;
import org.python.pydev.debug.model.PyDebugTarget;
import org.python.pydev.debug.model.PySourceLocator;
import org.python.pydev.debug.model.remote.RemoteDebugger;
import org.python.pydev.debug.pyunit.PyUnitServer;
import org.python.pydev.debug.pyunit.PyUnitView;
import org.python.pydev.plugin.PydevPlugin;
import org.python.pydev.runners.SimpleRunner;


/**
* Launches Python process, and connects it to Eclipse's debugger.
* Waits for process to complete.
*
* Modeled after org.eclipse.jdt.internal.launching.StandardVMDebugger.
*/
public class PythonRunner {

    /**
     * Launches the configuration
     *
     * The code is modeled after Ant launching example.
     */
    public static void run(final PythonRunnerConfig config, ILaunch launch, IProgressMonitor monitor)
            throws CoreException, IOException {

        try {
            PyUnitServer pyUnitServer = null;
            if (config.isUnittest()) {
                pyUnitServer = config.createPyUnitServer(config, launch);
                PyUnitView.registerPyUnitServer(pyUnitServer);
            }

            if (config.isDebug) {
                runDebug(config, launch, monitor);

            } else { //default - just configured by command line (the others need special attention)
                doIt(config, monitor, config.envp, config.getCommandLine(true), config.workingDirectory, launch);
            }

        } catch (final JDTNotAvailableException e) {
            Log.log(e);
            final Display display = Display.getDefault();
            display.syncExec(new Runnable() {

                public void run() {
                    MessageDialog.openError(display.getActiveShell(), "Unable to run the selected configuration.",
                            e.getMessage());
                }

            });
        }
    }

    /**
     * Launches the config in the debug mode.
     *
     * Loosely modeled upon Ant launcher.
     * @throws JDTNotAvailableException
     */
    private static void runDebug(PythonRunnerConfig config, ILaunch launch, IProgressMonitor monitor)
            throws CoreException, IOException, JDTNotAvailableException {
        if (monitor == null)
            monitor = new NullProgressMonitor();
        IProgressMonitor subMonitor = new SubProgressMonitor(monitor, 5);
        subMonitor.beginTask("Launching python", 1);

        // Launch & connect to the debugger       
        RemoteDebugger debugger = new RemoteDebugger();
        debugger.startConnect(subMonitor, config);
        subMonitor.subTask("Constructing command_line...");
        String[] cmdLine = config.getCommandLine(true);

        Process p = createProcess(launch, config.envp, cmdLine, config.workingDirectory);
        HashMap<Object, Object> processAttributes = new HashMap<Object, Object>();
        processAttributes.put(IProcess.ATTR_CMDLINE, config.getCommandLineAsString());
        processAttributes.put(Constants.PYDEV_DEBUG_IPROCESS_ATTR, Constants.PYDEV_DEBUG_IPROCESS_ATTR_TRUE);

        //Set the debug target before registering with the debug plugin (we want it before creating the console).
        PyDebugTarget t = new PyDebugTarget(launch, null, config.resource, debugger, config.project);
        IProcess process;
        try {
            process = registerWithDebugPluginForProcessType(config.getRunningName(), launch, p, processAttributes,
                    config);
            t.process = process;
        } finally {
            t.finishedInit = true;
        }

        subMonitor.subTask("Waiting for connection...");
        Socket socket = null;
        try {
            socket = debugger.waitForConnect(subMonitor, p, process);
            if (socket == null) {
                debugger.dispose();
                return;
            }
        } catch (Exception ex) {
            process.terminate();
            p.destroy();
            String message = "Unexpected error setting up the debugger";
            if (ex instanceof SocketTimeoutException)
                message = "Timed out after " + Float.toString(config.acceptTimeout / 1000)
                        + " seconds while waiting for python script to connect.";
            throw new CoreException(PydevDebugPlugin.makeStatus(IStatus.ERROR, message, ex));
        }
        subMonitor.subTask("Done");
        // hook up debug model, and we are off & running
        launch.setSourceLocator(new PySourceLocator());
        t.startTransmission(socket); // this starts reading/writing from sockets
        t.initialize();
        t.addConsoleInputListener();
    }

    private static IProcess doIt(PythonRunnerConfig config, IProgressMonitor monitor, String[] envp, String[] cmdLine,
            File workingDirectory, ILaunch launch) throws CoreException {
        if (monitor == null)
            monitor = new NullProgressMonitor();
        IProgressMonitor subMonitor = new SubProgressMonitor(monitor, 5);

        subMonitor.beginTask("Launching python", 1);

        // Launch & connect to the debugger       
        subMonitor.subTask("Constructing command_line...");
        String commandLineAsString = SimpleRunner.getArgumentsAsStr(cmdLine);
        //System.out.println("running command line: "+commandLineAsString);
        Map<Object, Object> processAttributes = new HashMap<Object, Object>();

        processAttributes.put(IProcess.ATTR_CMDLINE, commandLineAsString);

        subMonitor.subTask("Exec...");

        //it was dying before register, so, I made this faster to see if this fixes it
        Process p = createProcess(launch, envp, cmdLine, workingDirectory);

        IProcess process;
        String label = cmdLine[cmdLine.length - 1];

        //in the interactive session, we'll just create the process, it won't actually be registered
        //in the debug plugin (the communication is all done through xml-rpc).
        if (config.isInteractive) {
            throw new RuntimeException("Interactive not supported here!");
        }
        process = registerWithDebugPluginForProcessType(label, launch, p, processAttributes, config);

        // Registered the process with the debug plugin
        subMonitor.subTask("Done");
        return process;
    }

    /**
     * Actually creates the process (and create the encoding config file)
     */
    @SuppressWarnings("deprecation")
    private static Process createProcess(ILaunch launch, String[] envp, String[] cmdLine, File workingDirectory)
            throws CoreException {
        //Not using DebugPlugin.ATTR_CONSOLE_ENCODING to provide backward compatibility for eclipse 3.2
        String encoding = launch.getAttribute(IDebugUIConstants.ATTR_CONSOLE_ENCODING);
        if (encoding != null && encoding.trim().length() > 0) {
            String[] s = new String[envp.length + 3];
            System.arraycopy(envp, 0, s, 0, envp.length);

            //This is used so that we can get code-completion in a debug session.
            s[s.length - 3] = "PYDEV_COMPLETER_PYTHONPATH="
                    + PydevPlugin.getBundleInfo().getRelativePath(new Path("pysrc")).toString();

            s[s.length - 2] = "PYDEV_CONSOLE_ENCODING=" + encoding;
            //In Python 3.0, we can use the PYTHONIOENCODING.
            s[s.length - 1] = "PYTHONIOENCODING=" + encoding;
            envp = s;
        }
        Process p = DebugPlugin.exec(cmdLine, workingDirectory, envp);
        if (p == null) {
            throw new CoreException(PydevDebugPlugin.makeStatus(IStatus.ERROR, "Could not execute python process.",
                    null));
        }
        PythonRunnerCallbacks.afterCreatedProcess.call(p);
        return p;
    }

    /**
     * The debug plugin needs to be notified about our process.
     * It'll then display the appropriate UI.
     */
    private static IProcess registerWithDebugPluginForProcessType(String label, ILaunch launch, Process p,
            Map<Object, Object> processAttributes, PythonRunnerConfig config) {
        processAttributes.put(IProcess.ATTR_PROCESS_TYPE, config.getProcessType());
        processAttributes.put(IProcess.ATTR_PROCESS_LABEL, label);
        processAttributes.put(Constants.PYDEV_CONFIG_RUN, config.run);
        processAttributes.put(Constants.PYDEV_ADD_RELAUNCH_IPROCESS_ATTR,
                Constants.PYDEV_ADD_RELAUNCH_IPROCESS_ATTR_TRUE);
        processAttributes.put(DebugPlugin.ATTR_CAPTURE_OUTPUT, "true");

        return DebugPlugin.newProcess(launch, p, label, processAttributes);
    }

}
TOP

Related Classes of org.python.pydev.debug.ui.launching.PythonRunner

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.